<!DOCTYPE html>
<html>

<head>
    <meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
<meta name="apple-mobile-web-app-capable" content="yes"/>
<title>3.3 BOOTLOADER | pansis.io</title>
<link rel="shortcut icon" href="https://github.pansis.site/favicon.ico">
<link href="https://github.pansis.site/styles/main.css" rel="stylesheet">
<link href="//at.alicdn.com/t/c/font_1678829_b85ccgkdqkr.css" rel="stylesheet">
<link href="//cdnjs.cloudflare.com/ajax/libs/KaTeX/0.10.0/katex.min.css" rel="stylesheet">
<link rel="alternate" type="application/rss+xml" title="pansis.io » Feed" href="https://github.pansis.site/atom.xml">
        <meta name="description" content="一、BootLoader
1、概念
Boot Loader 就是在操作系统内核运行之前运行的一段小程序。
2、功能

初始化硬件设备
建立内存空间的映射图
将系统的软硬件环境带到一个合适的状态，以便为最终调用操作系统内核准备好正确的环境。
..." />
        <meta name="keywords" content="嵌入式系统" />
        <!-- OG -->
        <meta property="og:locale" content="zh_CN">
        <meta property="og:title" content="3.3 BOOTLOADER" />
        <meta property="og:type" content="article" />
        <meta property="og:description" content="一、BootLoader
1、概念
Boot Loader 就是在操作系统内核运行之前运行的一段小程序。
2、功能

初始化硬件设备
建立内存空间的映射图
将系统的软硬件环境带到一个合适的状态，以便为最终调用操作系统内核准备好正确的环境。
...">
        <meta property="og:url" content="https://github.pansis.site/post/3.3 BOOTLOADER/" />
        <meta property="og:site_name" content="pansis.io">
        <meta property="og:updated_time" content="2024-11-15">
        <meta property="og:image" content="" />
        <meta property="og:image:secure_url" content="">
        <meta property="og:image:alt" content="3.3 BOOTLOADER">
        <!-- Twitter (post.ejs) -->
        <meta name="twitter:card" content="summary_large_image">
        <meta name="twitter:title" content="3.3 BOOTLOADER">
        <meta name="twitter:description" content="一、BootLoader
1、概念
Boot Loader 就是在操作系统内核运行之前运行的一段小程序。
2、功能

初始化硬件设备
建立内存空间的映射图
将系统的软硬件环境带到一个合适的状态，以便为最终调用操作系统内核准备好正确的环境。
...">
        <!-- <meta name="twitter:site" content="@WBoy0609">
        <meta name="twitter:creator" content="@WBoy0609"> -->
        <meta name="twitter:image" content="">
</head>

<body>
    <div class="main animated">
        <div class="header animated fadeInDown">
    <div class="site_title_container">
        <div class="site_title">
            <a href="https://github.pansis.site">pansis.io</a>
        </div>
    </div>
    <div class="my_socials">
        
            
        
            
        
            
        
            
        
            
        
            
        
            
        
        <a href="https://github.pansis.site/atom.xml" title="rss" target="_blank"><i class="iconfont icon-rss"></i></a>
    </div>
</div>

    <div class="header_menu">
        
            
                <a href="/" class="menu">首页</a>
            
        
            
                <a href="/tag/GWAaV2nvk/" class="menu">程序设计课程</a>
            
        
            
                <a href="/tag/24hangc" class="menu">比赛</a>
            
        
            
                <a href="/tag/L7r9STb75/" class="menu">Python教程</a>
            
        
            
                <a href="/tags" class="menu">分类</a>
            
        
        <div class="gridea-search-div">
            <form id="gridea-search-form" action="https://github.pansis.site/search/">
                <input class="gridea-search-input" autocomplete="off" spellcheck="false" name="q"/>
            </form>
        </div>
    </div>

            <div class="autopagerize_page_element">
                <div class="content">
                    <div class="post_page">
                        <div class="post animated fadeInDown">
                            <div class="post_title post_detail_title">
                                <h2>
                                    3.3 BOOTLOADER
                                </h2>
                                <span class="article-info">
                                    2024-11-15, 1944 words, 8 min read
                                </span>
                            </div>
                            <div class="post_content markdown">
                                <p class="md_block">
                                    <span class="md_line md_line_start md_line_end">
                                        <h2 id="一-bootloader">一、BootLoader</h2>
<h4 id="1-概念">1、概念</h4>
<p>Boot Loader 就是在操作系统内核运行之前运行的一段小程序。</p>
<h4 id="2-功能">2、功能</h4>
<ul>
<li>初始化硬件设备</li>
<li>建立内存空间的映射图</li>
<li>将系统的软硬件环境带到一个合适的状态，以便为最终调用操作系统内核准备好正确的环境。</li>
<li>将内核映象读到 RAM 中，然后跳转到内核的入口去运行，即开始启动操作系统</li>
</ul>
<h4 id="3-安装介质">3、安装介质</h4>
<p>系统加电或复位后，所有的CPU 通常都从某个由CPU 制造商预先安排的地址上取指令。此位置即为BootLoader的第一个指令。</p>
<figure data-type="image" tabindex="1"><img src="http://cos.pansis.site/image-20241115154132204.png?abc123" alt="image-20241115154132204" loading="lazy"></figure>
<h4 id="4-boot-loader-的启动过程分类">4、Boot Loader 的启动过程分类</h4>
<ul>
<li>单阶段（Single   Stage）</li>
<li>多阶段（Multi-Stage）</li>
</ul>
<p>通常，多阶段的Boot Loader 能提供更为复 杂的功能，以及更好地可移植性</p>
<p>从固态存储设备上启动的Boot Loader 大多都是两个阶段的启动过程，下面均以两阶段为例</p>
<h4 id="5-boot-loader-的操作模式">5、Boot Loader 的操作模式</h4>
<ul>
<li>启动加载（Boot loading）模式 ：这种模式是Boot Loader 的正常工作模式</li>
<li>下载（Downloading）模式：目标机的Boot Loader通过串口或网络等通信手段从主机（Host）下载文件</li>
</ul>
<h2 id="二-boot-loader的典型结构框架">二、Boot Loader的典型结构框架</h2>
<p>（以两阶段为例）</p>
<h4 id="1-执行任务">1、执行任务</h4>
<ol>
<li>通常包括以下步骤(按执行的先后顺序)：
<ul>
<li>硬件设备初始化</li>
<li>为加载Boot Loader 的 stage2 准备 RAM 空间</li>
<li>拷贝Boot Loader 的 stage2 到 RAM 空间中</li>
<li>设置好堆栈</li>
<li>跳转到stage2 的C 入口点</li>
</ul>
</li>
<li>Boot Loader 的 stage2 通常包括以下步骤(按执行的先后顺序)：
<ul>
<li>初始化本阶段要使用到的硬件设备</li>
<li>检测系统内存映射(Memory Map)</li>
<li>将kernel 映像和根文件系统映像从flash 上读到RAM 空间中</li>
<li>为内核设置启动参数</li>
<li>调用内核</li>
</ul>
</li>
</ol>
<h3 id="2-boot-loader-的-stage1-阶段">2、Boot Loader 的 stage1 阶段</h3>
<h4 id="1硬件设备初始化">（1）硬件设备初始化</h4>
<p>1、目的：为stage2及kernel的执行准备好 基本硬件环境</p>
<p>2、过程：</p>
<ul>
<li>屏蔽所有的中断：为中断提供服务通常是OS或设备驱动程序的重 要责任，在Boot Loader阶段不必响应任何中断 （中断屏蔽可以通过写CPU 的中断屏蔽寄存器或 状态寄存器来完成，比如ARM 的CPSR 寄存器）</li>
<li>设置CPU 的速度和时钟频率</li>
<li>RAM 初始化：包括正确地设置系统中内存控制器的功能寄存器 以及内存（Memory Bank）的控制寄存器等</li>
<li>初始化LED：通过GPIO 来驱动LED，其目的是表明 系统的状态是OK 还是Error。若板子上无LED， 也可通过初始化UART向串口打印Boot Loader的 Logo字符信息来完成</li>
<li>关闭CPU 内部的指令／数据Cache</li>
</ul>
<h4 id="2为stage2-准备-ram-空间">（2）为stage2 准备 RAM 空间</h4>
<ol>
<li>RAM空间大小：
<ul>
<li>stage2 可执行映象的大小+堆栈空间（stage2 通常是 C 语言代码，需要堆栈）</li>
<li>最好对齐到memory page大小(通常是 4KB)</li>
<li>一般而言1MB已足够</li>
</ul>
</li>
<li>地址范围：
<ul>
<li>可以随意安排</li>
<li>推荐将stage2 安排到整个RAM空间的最顶1MB  亦即(RamEnd-1MB)开始处</li>
</ul>
</li>
<li>RAM空间有效性测试
<ul>
<li>必须确保所安排的地址范围的确为可读写的 RAM 空间</li>
<li>以内存页为被测单位，测试每个页面头两个字是否可 读写test_mempage
<ul>
<li>保存被测页面头两个字的内容</li>
<li>向这两个字中写入任意的数字。</li>
<li>立即将这两个字的内容读回。应当与写入的内容一致，否则此 页面地址范围不是一段有效的RAM 空间</li>
<li>再次向这两个字中写入任意的数字</li>
<li>立即将这两个字的内容读回。判断依据同3</li>
<li>恢复这两个字的原始内容</li>
</ul>
</li>
<li>测试结束后，为了得到一段干净的RAM 空 间，可以将所安排的RAM 空间范围进行清 零操作</li>
</ul>
</li>
</ol>
<h4 id="3拷贝stage2-到-ram-中">（3）拷贝stage2 到 RAM 中</h4>
<p>拷贝时要确定：Stage2的可执行映象在固态存储设备的存 放起始地址和终止地址 、RAM 空间的起始地址</p>
<h4 id="4设置堆栈指针sp">（4）设置堆栈指针sp</h4>
<p>通常设置在上述1MB RAM 空间的最顶端     sp=(stage2_end-4)</p>
<h4 id="5跳转到stage2-的c-入口点">（5）跳转到stage2 的C 入口点</h4>
<ol>
<li>方法：利用trampoline(蹦床)，目的：提供参数，获取返回值</li>
<li>trampoline
<ul>
<li>用汇编语言写一段trampoline 小程序，并将它来作为stage2  可执行映象的执行入口点</li>
<li>在trampoline中用 CPU 跳转指令跳入 main() 函数中去执行</li>
<li>当main() 函数返回时，CPU 执行路径显然再次回到 trampoline 程序</li>
</ul>
</li>
</ol>
<img src="http://cos.pansis.site/image-20241115155848233.png?abc123" alt="image-20241115155848233" style="zoom:50%;" />
<h3 id="3-boot-loader-的-stage2-阶段">3、Boot Loader 的 stage2 阶段</h3>
<h4 id="1初始化要用的硬件设备">（1）初始化要用的硬件设备</h4>
<ol>
<li>通常包括：
<ul>
<li>初始化至少一个串口，以便和终端用户进行I/O 输出信息</li>
<li>初始化计时器等</li>
<li>在初始化这些设备之前，也可重新把LED 灯点亮，以表明已 进入main() 函数执行</li>
<li>设备初始化完成后，可以输出一些打印信息，程序名字字符串、版本号等</li>
</ul>
</li>
</ol>
<h4 id="2检测系统内存映射">（2）检测系统内存映射</h4>
<ol>
<li>必须知道CPU 预留的全部RAM 地址空间中的哪些被真正映射到RAM 地址单元， 哪些是处于“unused&quot; 状态</li>
<li>内存映射的描述</li>
</ol>
<img src="http://cos.pansis.site/image-20241115160949879.png?abc123" alt="image-20241115160949879" style="zoom:50%;" />
<ol>
<li>内存映射检测算法
<ul>
<li>数组初始化，每个区域的used标志设为0</li>
<li>将整个空间中所有页面的前32位（4个字节）写为0</li>
<li>依次检测每个页面是否有效（使用test_mempage算法）</li>
<li>若当前页面无效
<ul>
<li>若当前区域已映射，则当前区域检测结束</li>
</ul>
</li>
<li>若当前页面有效
<ul>
<li>判断该页面是否由其他页面映射而来，若是同3.1</li>
<li>否则若当前区域已映射，则增加有效页面到当前区域中</li>
<li>若当前区域为一个新的区域，则初始化该区域并增加当 前页面到当前区域中</li>
</ul>
</li>
</ul>
</li>
</ol>
<h4 id="3加载映像">（3）加载映像</h4>
<ol>
<li>规划内存占用的布局，包括： 内核映像所占用的内存范围、 根文件系统所占用的内存范围</li>
<li>内核映像所占用的内存范围：
<ul>
<li>一般从(MEM_START＋ 0x8000) 开始约1MB的内存范围内（嵌入式Linux 的内核一般都不超过1MB）</li>
<li>从MEM_START 到MEM_START＋ 0x8000 这段 32KB 大小的内存的作用：Linux 内核要在这段内存中放置一些全局数 据结构，如：启动参数和内核页表等信息</li>
</ul>
</li>
<li>根文件系统所占用的内存范围：
<ul>
<li>一般从 MEM_START+0x0010,0000 开始。如果用 Ramdisk 作为根文件系统映像，则其解压后 的大小一般是1MB</li>
<li>加载映像：从Flash 上拷贝（ARM 的嵌入式CPU 通常都在统一的 内存地址空间中）（从Flash 上读取数据与从 RAM 单元中读取 数据并没有什么不同。用一个简单的循环就 可完成从Flash 设备上拷贝映像的工作）</li>
</ul>
</li>
</ol>
<h4 id="4设置内核的启动参数">（4）设置内核的启动参数</h4>
<p>boot_loader设置的参数有：</p>
<ul>
<li>内核参数：如页面大小、根设备</li>
<li>内存映射情况</li>
<li>命令行参数</li>
<li>initrd映像参数：起始地址，大小</li>
<li>Ramdisk参数： 解压后的大小</li>
</ul>
<h4 id="5调用内核">（5）调用内核</h4>
<ul>
<li>调用方法：直接跳转到内核的第一条指令处，亦即RAM中内核被加载的地址处</li>
<li>对于ARM Linux系统，在跳转之前必须满足：
<ul>
<li>CPU 寄存器的设置： R0＝0 、R1＝机器类型ID 、R2＝传递给内核的启动参数起始地址</li>
<li>CPU 模式：  必须禁止中断（IRQs和FIQs）、CPU必须处于SVC模式</li>
<li>Cache 和 MMU 的设置： MMU 必须关闭、 指令Cache 可以打开也可以关闭、数据Cache 必须关闭</li>
</ul>
</li>
</ul>
<br />
                                            
                                </p>
                            </div>
                            <div class="post_footer">
                                
                                    <div class="meta">
                                        <div class="info"><span class="field tags"><i class="iconfont icon-tag-sm"></i>
                                                
                                                    <a href="https://github.pansis.site/tag/AVw14AAoK/" class="article-info">
                                                        嵌入式系统
                                                    </a>
                                                    
                                            </span>
                                        </div>
                                    </div>
                                    
                                        
                            </div>
                        </div>
                        
                            
                                <link rel="stylesheet" href="https://unpkg.com/gitalk/dist/gitalk.css">
<script src="https://unpkg.com/gitalk/dist/gitalk.min.js"></script>
<div id="gitalk-container" style="padding-bottom: 20px;"></div>
<script>
    var pageId = (location.pathname).substring(1, 49) // Ensure uniqueness and length less than 50
    pageId = pageId.endsWith('/') ? pageId.slice(0, -1) : pageId // 以斜杠结尾则去除
    var gitalk = new Gitalk({
        clientID: '9d5eba33618472c44a07',
        clientSecret: '065a85ed04333ceebfc4f01d7ca1674175730339',
        repo: 'fzxl2003.github.io',
        owner: 'fzxl2003',
        admin: ['fzxl2003'],
        id: pageId,
        distractionFreeMode: false  // Facebook-like distraction free mode
    })
    gitalk.render('gitalk-container')
</script>
                                    
                                        
                                                    
                    </div>
                </div>
            </div>
    </div>
    <div class="footer">
    
    <div class="powered_by">
        <a href="https://codeberg.org/kytrun/gridea-theme-one" target="_blank">Theme One,</a>
        <a href="https://open.gridea.dev/" target="_blank">Powered by Gridea&#65281;</a>
    </div>
    
    
        <div class="footer_slogan">
            Powered by <a href="https://github.com/getgridea/gridea" target="_blank">Gridea</a>
        </div>
    
    <div id="back_to_top" class="back_to_top">
        <span>△</span>
    </div>
    
</div>

<script src="https://github.pansis.site/media/scripts/util.js"></script>
        <link rel="stylesheet" href="//unpkg.com/@highlightjs/cdn-assets@11.5.1/styles/default.min.css">
        <script src="//unpkg.com/@highlightjs/cdn-assets@11.5.1/highlight.min.js"></script>
        <script>hljs.highlightAll();</script>
</body>

</html>